﻿using Infrastructure.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;

namespace Infrastructure.Filters
{
    public class SucceededResultFilter : IAsyncActionFilter, IOrderedFilter
    {
        private readonly IResultProvider _provider;
        public SucceededResultFilter(IResultProvider provider)
        {
            this._provider = provider;
        }
        /// <summary>
        /// 过滤器排序
        /// </summary>
        internal const int FilterOrder = 8888;

        /// <summary>
        /// 排序属性
        /// </summary>
        public int Order => FilterOrder;

        /// <summary>
        /// 处理规范化结果
        /// </summary>
        /// <param name="context"></param>
        /// <param name="next"></param>
        /// <returns></returns>
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            if (typeof(Controller).IsAssignableFrom(actionDescriptor.ControllerTypeInfo))
            {
                await next();
                return;
            }
            var actionExecutedContext = await next();
            if (actionExecutedContext.Exception == null && IsEnableRspContract(actionDescriptor))
            {
                if (actionExecutedContext.Result is BadRequestObjectResult badRequestObjectResult)
                {
                    var (validationResults, validateFaildMessage, modelState) = badRequestObjectResult.Value.OutputValidationInfo();
                    var result = _provider.OnValidateFailed(context, modelState, validationResults, validateFaildMessage);
                    if (result != null) actionExecutedContext.Result = result;
                }
                else
                {
                    var result = _provider.OnSucceeded(actionExecutedContext);
                    if (result != null) actionExecutedContext.Result = result;
                }
            }
        }

        internal bool IsEnableRspContract(ControllerActionDescriptor descriptor)
        {
            return (
                descriptor.ControllerTypeInfo.CustomAttributes.Any(x => typeof(EnableRspContractAttribute).IsAssignableFrom(x.AttributeType)) 
                || descriptor.MethodInfo.CustomAttributes.Any(x => typeof(EnableRspContractAttribute).IsAssignableFrom(x.AttributeType))
              )
              && !descriptor.MethodInfo.CustomAttributes.Any(x => typeof(IgnoreRspContractAttribute).IsAssignableFrom(x.AttributeType))
            ;
        }


        internal bool IsSkipResultContract(ControllerActionDescriptor descriptor)
        {
            var restFulType = _provider.GetType().GetCustomAttribute<ResultModelAttribute>().ModelType;
            var isSkip = descriptor.MethodInfo.GetMethodRealReturnType().HasImplementedRawGeneric(restFulType)
                  || descriptor.MethodInfo.CustomAttributes.Any(x => typeof(SkipResultContractAttribute).IsAssignableFrom(x.AttributeType) 
                  || typeof(ProducesResponseTypeAttribute).IsAssignableFrom(x.AttributeType)
                  || typeof(IApiResponseMetadataProvider).IsAssignableFrom(x.AttributeType));

            return isSkip;
        }
    }
}
